package xcmg.device.service.sale;

import com.github.pagehelper.PageInfo;
import yb.ecp.fast.infra.util.PageHelperPlus;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Cell;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import xcmg.device.dao.entity.company.DealerVehicleDO;
import xcmg.device.dao.entity.sale.SalesBillDO;
import xcmg.device.dao.entity.sale.SalesBillExportDO;
import xcmg.device.dao.entity.sale.SalesOutBillDO;
import xcmg.device.dao.entity.sale.SalesOutBillDetailDO;
import xcmg.device.dao.entity.warehouse.WarehouseInventoryDO;
import xcmg.device.dao.mapper.company.DealerVehicleMapper;
import xcmg.device.dao.mapper.sale.SalesBillDetailMapper;
import xcmg.device.dao.mapper.sale.SalesBillMapper;
import xcmg.device.dao.mapper.sale.SalesOutBillDetailMapper;
import xcmg.device.dao.mapper.sale.SalesOutBillMapper;
import xcmg.device.dao.mapper.warehouse.WarehouseDeliveryDetailMapper;
import xcmg.device.dao.mapper.warehouse.WarehouseInventoryMapper;
import xcmg.device.infra.DateUtil;
import xcmg.device.infra.ErrorCode;
import xcmg.device.infra.ExcelUtil;
import xcmg.device.infra.ExportUtil;
import xcmg.device.infra.FileUtil;
import xcmg.device.infra.StringUtil;
import xcmg.device.infra.enums.BillDesc;
import xcmg.device.service.GenDocumentService;
import xcmg.device.service.agent.ServiceBorrowOutService;
import xcmg.device.service.basic.MaterialsService;
import xcmg.device.service.company.CompanyInfoService;
import xcmg.device.service.threeGuaranteesPur.ThreeGuaranteesPurService;
import xcmg.device.service.vo.FunctionResult;
import xcmg.device.service.vo.basic.MaterialsVO;
import xcmg.device.service.vo.company.CompanyInfoVO;
import xcmg.device.service.vo.sale.SalesBillDetailInfoVO;
import xcmg.device.service.vo.sale.SalesBillDetailVO;
import xcmg.device.service.vo.sale.SalesBillVO;
import xcmg.device.service.vo.threeGuaranteesPur.ThreeGuaranteesPurDetailVO;
import xcmg.device.service.vo.warehouse.WarehouseInventoryVO;
import xcmg.device.util.CompanyUtil;
import yb.ecp.fast.feign.FastGenClient;
import yb.ecp.fast.infra.infra.PageCommonVO;
import yb.ecp.fast.infra.infra.SearchCommonVO;
import yb.ecp.fast.infra.util.ListUtil;

import javax.servlet.http.HttpServletResponse;
import java.io.InputStream;
import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * Created by wrg on 2019/4/22.
 */
@Service
public class SalesBillService {
    @Autowired
    private SalesBillMapper salesBillMapper;
    @Autowired
    private SalesBillDetailMapper salesBillDetailMapper;
    @Autowired
    private SalesBillDetailService salesBillDetailService;
    @Autowired
    private FastGenClient genClient;
    @Autowired
    private GenDocumentService genDocumentService;
    @Autowired
    private HttpServletResponse response;
    @Autowired
    private SalesOutBillDetailMapper salesOutBillDetailMapper;
    @Autowired
    private WarehouseDeliveryDetailMapper warehouseDeliveryDetailMapper;
    @Autowired
    private WarehouseInventoryMapper warehouseInventoryMapper;
    @Value("${spring.file.download.path}")
    private String filePath;

    private String templateExcelFileName = "SalesBillImport.xls";
    @Autowired
    private MaterialsService materialsService;
    @Autowired
    private ServiceBorrowOutService serviceBorrowOutService;
    @Autowired
    private DealerVehicleMapper dealerVehicleMapper;
    @Autowired
    private SalesOutBillMapper salesOutBillMapper;

    @Autowired
    private CompanyInfoService companyInfoService;

    @Autowired
    private SalesBillOutService salesBillOutService;

    public PageCommonVO list(SearchCommonVO<SalesBillVO> condition) {
        List<String> salesBillNoList = StringUtil.getStrSplitList(condition.getFilters().getSalesBillNo());
        condition.getFilters().setSalesBillList(salesBillNoList);

        PageCommonVO<SalesBillVO> pageCommonVO = new PageCommonVO<>();
        PageHelperPlus.orderBy("create_date desc");
        PageHelperPlus.startPage(condition.getPageNum(), condition.getPageSize());
        List<SalesBillDO> doList = salesBillMapper.list(condition.getFilters());
        List<SalesBillVO> voList = new ArrayList<>();
        for (SalesBillDO entity : doList) {
            SalesBillVO model = new SalesBillVO();
            BeanUtils.copyProperties(entity, model);
            voList.add(model);
        }
        pageCommonVO.setPageInfo(new PageInfo<>(doList));
        pageCommonVO.setPageInfoList(voList);
        return pageCommonVO;
    }

    public PageCommonVO salasOutBillList(SearchCommonVO<SalesBillVO> condition) {
        PageCommonVO<SalesBillVO> pageCommonVO = new PageCommonVO<>();
        PageHelperPlus.orderBy("create_date desc");
        PageHelperPlus.startPage(condition.getPageNum(), condition.getPageSize());
        List<SalesBillDO> doList = salesBillMapper.salasOutBillList(condition.getFilters());
        List<SalesBillVO> voList = new ArrayList<>();
        for (SalesBillDO entity : doList) {
            SalesBillVO model = new SalesBillVO();
            BeanUtils.copyProperties(entity, model);
            voList.add(model);
        }
        pageCommonVO.setPageInfo(new PageInfo<>(doList));
        pageCommonVO.setPageInfoList(voList);
        return pageCommonVO;
    }


    public SalesBillDetailInfoVO detail(String id) {
        SalesBillDO entity = salesBillMapper.selectByPrimaryKey(id);
        SalesBillVO model = new SalesBillVO();
        BeanUtils.copyProperties(entity, model);
        SalesBillDetailVO condition = new SalesBillDetailVO();
        condition.setSalesBillNo(entity.getSalesBillNo());
        List<SalesBillDetailVO> list = salesBillDetailService.list(condition);
        SalesBillDetailInfoVO result = new SalesBillDetailInfoVO();
        result.setSalesBillVO(model);
        result.setMaterialList(list);
        return result;
    }

    @Transactional(rollbackFor = Exception.class)
    public FunctionResult<String> add(SalesBillVO salesBillVO, String userId, String orgId) throws Exception {
        FunctionResult<String> result = new FunctionResult<>();
        //单据类型如果是赠送校验用户车辆额度
      /*  boolean checkQuota = checkQuota(salesBillVO, orgId, result);
        if (checkQuota) {
            return result;
        }*/

        String id = genClient.newGuidText().getValue();
        if (StringUtils.isBlank(id)) {
            result.setCode(ErrorCode.Failure);
            return result;
        }

        Date date = new Date();
        String salasBillNo = genDocumentService.getDocumentNo(BillDesc.SalesNo);

        List<SalesBillDetailVO> detailVOList = getDetailVOList(salesBillVO, userId, orgId, date, salasBillNo);
        ErrorCode errorCode = salesBillDetailService.add(detailVOList);
        if (ErrorCode.Success != errorCode) {
            throw new Exception("新增销售单失败");
        }

        SalesBillDO record = getSalesBillDO(salesBillVO, userId, orgId, id, date, salasBillNo);
        int insertCount = salesBillMapper.insertSelective(record);
        if (insertCount <= 0) {
            throw new Exception("新增销售单失败");
        }
        // 如果是借用单转销售并且是提交状态更新借用单数量
        Short status = record.getStatus();
        String borrowBillNo = record.getBorrowBillNo();
        updateServiceBorrowResaleQty(detailVOList, status, borrowBillNo, orgId);

        result.setCode(ErrorCode.Success);
        result.setValue(id);
        return result;
    }

    private boolean checkQuota(SalesBillVO salesBillVO, String orgId, FunctionResult<String> result) {
        Short billType = salesBillVO.getBillType();
        if (3 == billType) {
            String useMachineNo = salesBillVO.getUseMachineNo();
            //获取整机额度
            DealerVehicleDO vehicleDO = dealerVehicleMapper.getAvailableVehicleInfo(salesBillVO.getClientName(), orgId, useMachineNo);
            if (null == vehicleDO) {
                result.setCode(ErrorCode.IllegalArument);
                return true;
            }
            List<SalesBillDetailVO> detailVOList = salesBillVO.getDetailVOList();
            BigDecimal universalQuota = BigDecimal.ZERO;
            BigDecimal maintenanceQuota = BigDecimal.ZERO;
            for (SalesBillDetailVO salesBillDetailVO : detailVOList) {
                universalQuota = universalQuota.add(salesBillDetailVO.getApplyQty().multiply(salesBillDetailVO.getAdjustedSinglePrice()));
                maintenanceQuota = maintenanceQuota.add(salesBillDetailVO.getApplyQty().multiply(salesBillDetailVO.getAdjustedSinglePrice()));
            }

            Short giveQuotaType = salesBillVO.getGiveQuotaType();
            if (1 == giveQuotaType) {//通用
                BigDecimal universalSendAmount = vehicleDO.getUniversalSendAmount();
                BigDecimal universalUseAmount = vehicleDO.getUniversalUseAmount().add(universalQuota).setScale(2, BigDecimal.ROUND_DOWN);
                BigDecimal universalLaveAmount = universalSendAmount.subtract(universalUseAmount).setScale(2, BigDecimal.ROUND_DOWN);
                if (universalLaveAmount.compareTo(BigDecimal.ZERO) < 0) {
                    result.setCode(ErrorCode.TheUsageQuotaIsGreaterThanCreditLimit);
                    return true;
                }
            }

            if (2 == giveQuotaType) {//保养
                BigDecimal maintenanceSendAmount = vehicleDO.getMaintenanceSendAmount();
                BigDecimal maintenanceUseAmount = vehicleDO.getMaintenanceUseAmount().add(maintenanceQuota).setScale(2, BigDecimal.ROUND_DOWN);
                BigDecimal maintenanceLaveAmount = maintenanceSendAmount.subtract(maintenanceUseAmount).setScale(2, BigDecimal.ROUND_DOWN);
                if (maintenanceLaveAmount.compareTo(BigDecimal.ZERO) < 0) {
                    result.setCode(ErrorCode.TheUsageQuotaIsGreaterThanCreditLimit);
                    return true;
                }
            }
        }
        return false;
    }

    private void updateServiceBorrowResaleQty(List<SalesBillDetailVO> detailVOList, Short status, String borrowBillNo, String orgId) throws Exception {
        if (1 != status || StringUtils.isBlank(borrowBillNo)) {
            return;
        }
        for (SalesBillDetailVO salesBillDetailVO : detailVOList) {
            // 校验转销售数量
            String materialNo = salesBillDetailVO.getMaterialNo();
            BigDecimal applyQty = salesBillDetailVO.getApplyQty();
            BigDecimal remainingQty = serviceBorrowOutService.getRemainingQty(borrowBillNo, materialNo, orgId);
            if (null == remainingQty || remainingQty.compareTo(applyQty) < 0) {
                throw new Exception("新增销售单数量不允许大于借用单剩余数量，最大剩余数量为:" + remainingQty);
            }
            //更新转销售数量
            boolean result = serviceBorrowOutService.updateResaleQty(borrowBillNo, materialNo, orgId, applyQty, BigDecimal.ZERO);
            if (!result) {
                throw new Exception("新增销售单更新转销售数量失败");
            }
        }
    }

    private List<SalesBillDetailVO> getDetailVOList(SalesBillVO salesBillVO, String userId, String orgId, Date date, String salasBillNo) {
        List<SalesBillDetailVO> detailVOList = salesBillVO.getDetailVOList();
        BigDecimal totalOrderPrice = BigDecimal.ZERO;
        BigDecimal costTotal = BigDecimal.ZERO;
        for (SalesBillDetailVO x: detailVOList) {
            x.setSalesBillNo(salasBillNo == null ? salesBillVO.getSalesBillNo() : salasBillNo);
            x.setCreateDate(date);
            x.setCreateId(userId);
            x.setUpdateDate(date);
            x.setUpdateId(userId);
            x.setOrgId(orgId);
            x.setStatus(salesBillVO.getStatus());
            BigDecimal applyQty = x.getApplyQty() == null ?  BigDecimal.ZERO:x.getApplyQty() ;
            BigDecimal costPrice = x.getCostPrice() == null ? BigDecimal.ZERO: x.getCostPrice();
            BigDecimal adjustedSinglePrice = x.getAdjustedSinglePrice() == null ? BigDecimal.ZERO: x.getAdjustedSinglePrice();

            totalOrderPrice = totalOrderPrice.add(applyQty.multiply(adjustedSinglePrice));
            costTotal = costTotal.add(costPrice.multiply(applyQty));
        }
        salesBillVO.setTotalOrderPrice(totalOrderPrice);
        salesBillVO.setCostTotal(costTotal);
        return detailVOList;
    }

    private SalesBillDO getSalesBillDO(SalesBillVO salesBillVO, String userId, String orgId, String id, Date date, String salasBillNo) {
        SalesBillDO record = new SalesBillDO();
        BeanUtils.copyProperties(salesBillVO, record);
        record.setSalesBillNo(salasBillNo);
        record.setId(id);
        record.setCreateDate(date);
        record.setCreateId(userId);
        record.setUpdateDate(date);
        record.setUpdateId(userId);
        record.setOrgId(orgId);
        record.setApplyDate(new Date());
        return record;
    }

    @Transactional(rollbackFor = Exception.class)
    public ErrorCode delete(List<String> ids, String orgId) throws Exception {
        for (String id : ids) {
            deleteSalasBillLogic(id, orgId);
        }
        return ErrorCode.Success;
    }

    private void deleteSalasBillLogic(String id, String orgId) throws Exception {
        SalesBillDO salesBillDO = salesBillMapper.selectByPrimaryKey(id);
        if (null == salesBillDO || StringUtils.isBlank(salesBillDO.getSalesBillNo())) {
            return;
        }
        Integer createOutboundStatus = salesBillDO.getCreateOutboundStatus();
        if (0 != createOutboundStatus) {
            throw new Exception("已创建销售出库单删除失败");
        }

        salesOutBillMapper.deleteBySalesBillNo(salesBillDO.getSalesBillNo());
        salesOutBillDetailMapper.deleteBySalesBillNo(salesBillDO.getSalesBillNo());

        SalesBillDetailVO condition = new SalesBillDetailVO();
        condition.setSalesBillNo(salesBillDO.getSalesBillNo());
        List<SalesBillDetailVO> oldSalesBillDetailVOList = salesBillDetailService.list(condition);

        ErrorCode errorCode = salesBillDetailService.delete(salesBillDO.getSalesBillNo());
        if (ErrorCode.Success != errorCode) {
            throw new Exception(ErrorCode.Failure.getDesc());
        }

        int deleteCount = salesBillMapper.deleteByPrimaryKey(id);
        if (deleteCount <= 0) {
            throw new Exception(ErrorCode.Failure.getDesc());
        }

        String borrowBillNo = salesBillDO.getBorrowBillNo();
        if (StringUtils.isBlank(borrowBillNo)) {
            return;
        }

        for (SalesBillDetailVO salesBillDetailVO : oldSalesBillDetailVOList) {
            Short status = salesBillDetailVO.getStatus();
            if (status == 0) {
                continue;
            }
            String materialNo = salesBillDetailVO.getMaterialNo();
            BigDecimal adjustedQty = salesBillDetailVO.getApplyQty();
            boolean result = serviceBorrowOutService.updateResaleQty(borrowBillNo, materialNo, orgId, BigDecimal.ZERO, adjustedQty);
            if (!result) {
                throw new Exception("新增销售单更新转销售数量失败");
            }
        }
    }

    @Transactional(rollbackFor = Exception.class)
    public FunctionResult<String> update(SalesBillVO salesBillVO, String userId, String orgId) throws Exception {
        FunctionResult<String> result = new FunctionResult<>();
        /*boolean checkQuota = checkQuota(salesBillVO, orgId, result);
        if (checkQuota) {
            return result;
        }*/

        Short status = salesBillVO.getStatus();
        String borrowBillNo = salesBillVO.getBorrowBillNo();
        modifiedWithNewSalesQty(salesBillVO, orgId, status, borrowBillNo);

        Date date = new Date();
        List<SalesBillDetailVO> detailVOList = getDetailVOList(salesBillVO, userId, orgId, date, null);
        ErrorCode errorCode = salesBillDetailService.update(detailVOList, salesBillVO.getSalesBillNo());
        if (ErrorCode.Success != errorCode) {
            throw new Exception("修改销售单失败");
        }

        SalesBillDO record = new SalesBillDO();
        BeanUtils.copyProperties(salesBillVO, record);
        record.setUpdateDate(date);
        record.setUpdateId(userId);
        int updateCount = salesBillMapper.updateByPrimaryKeySelective(record);
        if (updateCount <= 0) {
            throw new Exception("修改销售单失败");
        }

        result.setCode(ErrorCode.Success);
        result.setValue(salesBillVO.getId());
        return result;
    }

    //修改时修改转销售数量
    private void modifiedWithNewSalesQty(SalesBillVO salesBillVO, String orgId, Short status, String borrowBillNo) throws Exception {
        if (StringUtils.isBlank(borrowBillNo)) {
            return;
        }
        String salesBillNo = salesBillVO.getSalesBillNo();
        SalesBillDetailVO condition = new SalesBillDetailVO();
        condition.setSalesBillNo(salesBillNo);
        List<SalesBillDetailVO> oldSalesBillDetailVOList = salesBillDetailService.list(condition);
        List<SalesBillDetailVO> newDetailVOList = salesBillVO.getDetailVOList();
        for (SalesBillDetailVO salesBillDetailVO : newDetailVOList) {
            // 校验转销售数量
            checkResaleQty(orgId, status, borrowBillNo, salesBillDetailVO, oldSalesBillDetailVOList);
        }

        for (SalesBillDetailVO salesBillDetailVO : oldSalesBillDetailVOList) {
            //更新转销售数量
            String materialNo = salesBillDetailVO.getMaterialNo();
            Optional<SalesBillDetailVO> tempDO = newDetailVOList.stream().filter(x -> x.getMaterialNo().equals(salesBillDetailVO.getMaterialNo()) && status == 1).findFirst();
            BigDecimal adjustedQty = BigDecimal.ZERO;
            BigDecimal oldAdjustedQty = BigDecimal.ZERO;
            if (tempDO.isPresent()) {
                adjustedQty = tempDO.get().getApplyQty();
            }
            if (salesBillDetailVO.getStatus() != 0) {
                oldAdjustedQty = salesBillDetailVO.getApplyQty();
            }
            boolean result = serviceBorrowOutService.updateResaleQty(borrowBillNo, materialNo, orgId, adjustedQty, oldAdjustedQty);
            if (!result) {
                throw new Exception("新增销售单更新转销售数量失败");
            }
        }
    }

    private void checkResaleQty(String orgId, Short status, String borrowBillNo, SalesBillDetailVO salesBillDetailVO, List<SalesBillDetailVO> oldDetailVOList) throws Exception {
        if (status != 1) {
            return;
        }
        String materialNo = salesBillDetailVO.getMaterialNo();
        BigDecimal applyQty = salesBillDetailVO.getApplyQty();
        Optional<SalesBillDetailVO> tempDO = oldDetailVOList.stream().filter(x -> x.getMaterialNo().equals(salesBillDetailVO.getMaterialNo()) && x.getStatus() == 1).findFirst();
        BigDecimal oldAdjustedQty = BigDecimal.ZERO;
        if (tempDO.isPresent()) {
            oldAdjustedQty = tempDO.get().getApplyQty();
        }
        BigDecimal remainingQty = serviceBorrowOutService.getRemainingQty(borrowBillNo, materialNo, orgId);
        if (null == remainingQty || remainingQty.add(oldAdjustedQty).compareTo(applyQty) < 0) {
            throw new Exception("提交销售单数量不允许大于借用单剩余数量，最大剩余数量为:" + (remainingQty == null ? BigDecimal.ZERO : remainingQty).add(oldAdjustedQty));
        }
    }

    public void export(List<String> ids) throws Exception {
        List<SalesBillExportDO> voList = salesBillMapper.getExportListByIds(ids);
        invokeExport(voList);
    }

    public void exportAll(SalesBillVO condition) throws Exception {
        List<String> salesBillNoList = StringUtil.getStrSplitList(condition.getSalesBillNo());
        condition.setSalesBillList(salesBillNoList);
        PageHelperPlus.orderBy("create_date desc");
        List<SalesBillExportDO> doList = salesBillMapper.listExport(condition);
        invokeExport(doList);
    }

    private void invokeExport(List<SalesBillExportDO> voList) throws Exception {
        String title = "销售单数据导出";
        String[] rowsName = new String[]{"序号", "销售订单号", "客户名称", "服务人员", "订单类型", "申请日期", "收货人",
                "联系方式", "收货地址", "机型", "使用整机编号", "结算整机编号", "原因", "派工单号", "索赔单号", "赠送额度类型",
                "备注", "订单总价", "订单调整后总价","零件编码","零件名称","单位","申请数量","单价","申请总价","价格方案","调整后单价",
                "零件调整后总价","创建出库数量","实际出库数量"};
        List<Object[]> dataList = new ArrayList<>();
        int i = 1;
        for (SalesBillExportDO salesBillExportDO : voList) {
            Object[] objs = new Object[rowsName.length];
            objs[0] = i;
            objs[1] = salesBillExportDO.getSalesBillNo();
            objs[2] = salesBillExportDO.getClientName();
            objs[3] = salesBillExportDO.getServicePersonName();
            objs[4] = getBillType(salesBillExportDO.getBillType());
            objs[5] = (salesBillExportDO.getApplyDate() == null) ? "" : DateUtil.formatDateTime(salesBillExportDO.getApplyDate());
            objs[6] = salesBillExportDO.getConsignee();
            objs[7] = salesBillExportDO.getContactPhone();
            objs[8] = salesBillExportDO.getReceiptAddress();
            objs[9] = salesBillExportDO.getModel();
            objs[10] = salesBillExportDO.getUseMachineNo();
            objs[11] = salesBillExportDO.getSettleMachineNo();
            objs[12] = salesBillExportDO.getReason();
            objs[13] = salesBillExportDO.getWorkOrderNo();
            objs[14] = salesBillExportDO.getClaimOrderNo();
            if (null != salesBillExportDO.getGiveQuotaType()) {
                objs[15] = getGiveQuotaType(salesBillExportDO.getGiveQuotaType());
            } else {
                objs[15] = "";
            }
            objs[16] = salesBillExportDO.getRemark();
            objs[17] = salesBillExportDO.getTotalOrderPrice();
            objs[18] = salesBillExportDO.getAdjustedTotalPrice();
            objs[19] = salesBillExportDO.getMaterialNo();
            objs[20] = salesBillExportDO.getMaterialDes();
            objs[21] = salesBillExportDO.getUnit();
            objs[22] = salesBillExportDO.getApplyQty();
            objs[23] = salesBillExportDO.getSinglePrice();
            objs[24] = salesBillExportDO.getApplyTotalPrice();
            objs[25] = "";
            objs[26] = salesBillExportDO.getAdjustedSinglePrice();
            objs[27] = salesBillExportDO.getMaterialAdjustedTotalPrice();
            objs[28] = salesBillExportDO.getCreateOutboundQty();
            objs[29] = salesBillExportDO.getActualOutboundQty();
            dataList.add(objs);
            i = ++i;
        }

        ExportUtil exportUtil = new ExportUtil(title, rowsName, dataList);
        exportUtil.export(response);
    }

    private String getBillType(Short billType) {
        switch (billType) {
            case 1:
            default:
                return "普通";
            case 2:
                return "三包";
            case 3:
                return "赠送";
        }
    }

    private String getGiveQuotaType(Short quotaType) {
        switch (quotaType) {
            case 1:
            default:
                return "通用";
            case 2:
                return "保养";
        }
    }

    @Transactional(rollbackFor = Exception.class)
    public boolean updateByOutBound(String salesBillNo, String materialsNo, String orgId, BigDecimal totalOrderQty, BigDecimal outboundTotalQty) {
        if (totalOrderQty.compareTo(outboundTotalQty) == 0) {
            boolean success = salesBillDetailService.updateByOutBound(salesBillNo, materialsNo, 2);
            if (success) {
                Integer count = salesBillDetailService.checkWhetherNoOutbound(salesBillNo);
                if (count <= 0) {
                    success = salesBillMapper.updateStatusBySalesNo(salesBillNo, 2, null) > 0;
                }
            }
            return success;
        } else {
            return salesBillMapper.updateStatusBySalesNo(salesBillNo, 1, null) > 0;
        }
    }

    public List<SalesBillDetailVO> findDeliveryNum(String saleNo, String warehouseCode, String orgId) {
        SalesBillDetailVO condition = new SalesBillDetailVO();
        condition.setSalesBillNo(saleNo);
        List<SalesBillDetailVO> billDetailVOList = salesBillDetailService.list(condition);
        if (ListUtil.isNullOrEmpty(billDetailVOList)) {
            return null;
        }
        List<SalesBillDetailVO> voList = new ArrayList<>();
        for (SalesBillDetailVO salesBillDetailVO : billDetailVOList) {
            SalesBillDetailVO billDetailVO = new SalesBillDetailVO();
            billDetailVO.setMaterialNo(salesBillDetailVO.getMaterialNo());
            billDetailVO.setDeliveryNum(warehouseDeliveryDetailMapper.findOccupyNum(salesBillDetailVO.getMaterialNo(), orgId, warehouseCode));
            billDetailVO.setEnableNum(warehouseInventoryMapper.findEnableNum(salesBillDetailVO.getMaterialNo(), orgId, warehouseCode));
            voList.add(billDetailVO);
        }
        return voList;
    }

    /**
     * @Author: WangKe
     * @Description: 下载零件批量导入模板
     * @Date: 2018/3/1 0001
     */
    public void download() throws Exception {
        FileUtil.downLoadFile(response, filePath, templateExcelFileName);
    }

    public void addClaimOrdNo(String claimOrderNo, String id) throws Exception {
        if (salesBillMapper.countByClaimOrdNo(claimOrderNo) > 0) {
            throw new Exception("该索赔单号已存在，请勿重复添加");
        }
        salesBillMapper.addClaimOrderNo(claimOrderNo, id);
    }

    //导入
    public FunctionResult importExcel(InputStream in, String orgId) throws Exception {
        FunctionResult result = new FunctionResult();
        HSSFWorkbook wb = new HSSFWorkbook(in);
        HSSFSheet sheet = wb.getSheetAt(0);

        int totalRow = sheet.getLastRowNum();
        if (totalRow < 3) {
            result.setCode(ErrorCode.IllegalArument);
            result.setValue("导入模板不正确");
            return result;
        }
        int totalCell = sheet.getRow(2).getLastCellNum();
        if (totalCell != 4) {
            result.setCode(ErrorCode.IllegalArument);
            result.setValue("导入模板不正确");
            return result;
        }
        List<ThreeGuaranteesPurDetailVO> detailVOList = new ArrayList<>();
        List<ThreeGuaranteesPurDetailVO> errorDetailVOList = new ArrayList<>();
        for (int i = 3; i <= totalRow; i++) {
            HSSFRow curRow = sheet.getRow(i);
            ThreeGuaranteesPurDetailVO detailVO = new ThreeGuaranteesPurDetailVO();
            if (curRow == null) {
                continue;
            }
            if (isRowEmpty(curRow)) {
                continue;
            }
            String materialsNo = excelValue(curRow, 1);
            String qty = excelValue(curRow, 3);
            if (!isInteger(qty) || "0".equals(qty)) {
                detailVO.setErrorRow(i + 1);
                detailVO.setRemark("入库数量格式不正确");
                errorDetailVOList.add(detailVO);
                continue;
            }
            if (new BigDecimal(qty).compareTo(BigDecimal.valueOf(99999999.99)) > 0) {
                detailVO.setErrorRow(i + 1);
                detailVO.setRemark("入库数量过大");
                errorDetailVOList.add(detailVO);
                continue;
            }
            MaterialsVO materialsVO = materialsService.itemByNo(materialsNo, orgId);
            if (materialsVO == null) {
                detailVO.setErrorRow(i + 1);
                detailVO.setRemark("零件不存在");
                errorDetailVOList.add(detailVO);
                continue;
            }

            BigDecimal intQty = new BigDecimal(qty);
            BigDecimal max = new BigDecimal(99999999.99);
            if (intQty.compareTo(max) > 0) {
                intQty = max;
            }
            detailVO.setPurchaseQty(intQty);
            detailVO.setMaterialsNo(materialsVO.getMaterialsNo());
            detailVO.setMaterialsDesc(materialsVO.getMaterialsDes());
            detailVO.setPrice(materialsVO.getPrice());
            detailVO.setUnit(materialsVO.getUnit());
            detailVO.setPurchaseQty(intQty);
            detailVO.setIsMinimumBuy(materialsVO.getIsMinimumBuy());
            detailVO.setMinimumBuy(materialsVO.getMinimumBuy());
            detailVO.setTotalPrice(detailVO.getPrice() == null ? new BigDecimal(0) : detailVO.getPrice()
                    .multiply(detailVO.getPurchaseQty()));
            detailVO.setCostPrice(materialsVO.getStandardPrice());
            detailVO.setCostSubtotal(detailVO.getCostPrice() == null ? new BigDecimal(0) : detailVO.getCostPrice()
                    .multiply(detailVO.getPurchaseQty()));
            detailVOList.add(detailVO);
        }
        Map<String, BigDecimal> map = new HashMap<>();
        WarehouseInventoryVO request = new WarehouseInventoryVO();
        request.setOrgId(orgId);
        List<WarehouseInventoryDO> warehouseInventoryList = warehouseInventoryMapper.listForMaterial(request);
        for (WarehouseInventoryDO e : warehouseInventoryList) {
            map.put(e.getMaterialNo(), e.getAmount());
        }
        for (int i = 0; i < detailVOList.size(); i++) {
            if (map.containsKey(detailVOList.get(i).getMaterialsNo())) {
                detailVOList.get(i).setAmount(map.get(detailVOList.get(i).getMaterialsNo()));
            } else {
                detailVOList.get(i).setAmount(BigDecimal.ZERO);
            }
        }


        if (ListUtil.isNullOrEmpty(errorDetailVOList)) {
            result.setValue(ThreeGuaranteesPurService.deRepeat(detailVOList));
            result.setCode(ErrorCode.Success);
        } else {
            result.setValue(errorDetailVOList);
            result.setCode(ErrorCode.IllegalArument);
        }
        return result;
    }

    private String excelValue(HSSFRow curRow, Integer line) {
        Cell cell = curRow.getCell(line);
        String cellValue = "";
        if (null != cell) {
            // 以下是判断数据的类型
            switch (cell.getCellType()) {
                case HSSFCell.CELL_TYPE_NUMERIC: // 数字
                    DecimalFormat df = new DecimalFormat("0");
                    cellValue = df.format(cell.getNumericCellValue());
                    break;

                case HSSFCell.CELL_TYPE_STRING: // 字符串
                    cellValue = cell.getStringCellValue();
                    break;

                case HSSFCell.CELL_TYPE_BOOLEAN: // Boolean
                    cellValue = cell.getBooleanCellValue() + "";
                    break;

                case HSSFCell.CELL_TYPE_FORMULA: // 公式
                    cellValue = cell.getCellFormula() + "";
                    break;

                case HSSFCell.CELL_TYPE_BLANK: // 空值
                    cellValue = "";
                    break;

                case HSSFCell.CELL_TYPE_ERROR: // 故障
                    cellValue = "";
                    break;

                default:
                    cellValue = "";
                    break;
            }
        }
        return cellValue;
    }

    private boolean isInteger(String str) {
        if (null == str || "".equals(str)) {
            return false;
        }
        try {
            BigDecimal decimal = new BigDecimal(str);
        } catch (Exception e) {
            return false;
        }
        return true;
    }

    private boolean isRowEmpty(HSSFRow row) {
        for (int c = row.getFirstCellNum(); c < row.getLastCellNum(); c++) {
            HSSFCell cell = row.getCell(c);
            if (cell != null && cell.getCellType() != Cell.CELL_TYPE_BLANK && !yb.ecp.fast.infra.util.StringUtil.isNullOrSpace(ExcelUtil.getCellStringValue(cell))) {
                return false;
            }
        }
        return true;
    }

    @Transactional(rollbackFor = Exception.class)
    public boolean updateCreateOutStatus(String salesBillNo, String materialsNo, BigDecimal thisShipQty, BigDecimal actualQty,
                                         BigDecimal oldThisShipQty,Date outboundDate) {
        boolean success = salesBillDetailService.updateCreateOutQty(salesBillNo, materialsNo, thisShipQty, actualQty, oldThisShipQty);
        if (success) {
            Integer createStatus = getCreateStatus(salesBillNo, thisShipQty);
            Integer outStatus = getOutStatus(salesBillNo, actualQty);

            SalesBillDO record = new SalesBillDO();
            record.setCreateOutboundStatus(createStatus);
            record.setOutboundStatus(outStatus);
            record.setOutboundDate(outboundDate);
            record.setSalesBillNo(salesBillNo);

            success = salesBillMapper.updateBySalesBillNo(record) > 0;
        }

        return success;
    }

    private Integer getOutStatus(String salesBillNo, BigDecimal actualQty) {
        if (null == actualQty) {
            return null;
        }
        Integer outStatus;
        Integer outCount = salesBillDetailService.checkOutboundStatus(salesBillNo);
        if (outCount > 0) {
            outStatus = 1;
        } else {
            outStatus = 2;
        }

        return outStatus;
    }

    private Integer getCreateStatus(String salesBillNo, BigDecimal thisShipQty) {
        if (null == thisShipQty) {
            return null;
        }
        Integer createStatus;
        Integer createCount = salesBillDetailService.checkCreateOutboundStatus(salesBillNo);
        if (createCount > 0) {
            createStatus = 1;
        } else {
            createStatus = 2;
        }

        return createStatus;
    }

    @Transactional(rollbackFor = Exception.class)
    public boolean updateCreateOutQty(String salesOutBillNo, String materialsNo, boolean isDel, boolean check) {
        List<SalesOutBillDetailDO> outBillDetailDOList = salesOutBillDetailMapper.selectByBillNoMate(salesOutBillNo, materialsNo);
        for (SalesOutBillDetailDO salesOutBillDetailDO : outBillDetailDOList) {
            Short outboundStatus = salesOutBillDetailDO.getOutboundStatus();
            if (3 == outboundStatus) {
                continue;
            }

            String salesBillNo = salesOutBillDetailDO.getSalesBillNo();
            String materialNo = salesOutBillDetailDO.getMaterialNo();
            BigDecimal thisShipQty = salesOutBillDetailDO.getThisShipQty();
            if (check) {
                BigDecimal outboundQty = salesOutBillDetailDO.getOutboundQty();
                thisShipQty = thisShipQty.subtract(outboundQty == null ? BigDecimal.ZERO : outboundQty);
            }
            Short isState = salesOutBillDetailDO.getIsState();
            if (isDel && isState == 0) {//保存状态不扣减销售单创建出库单数量
                thisShipQty = BigDecimal.ZERO;
            }
            boolean updateResult = salesBillDetailService.updateOutQty(salesBillNo, materialNo, thisShipQty);
            if (!updateResult) {
                return false;
            }
        }
        if (isDel) {
            SalesOutBillDetailDO salesOutBillDetailDO = outBillDetailDOList.get(0);
            String salesBillNo = salesOutBillDetailDO.getSalesBillNo();
            Integer count = salesBillDetailMapper.getCrateQtyBigZeroCount(salesBillNo);
            if (count <= 0) {
                SalesBillDO salesBillDO = new SalesBillDO();
                salesBillDO.setCreateOutboundStatus(0);
                salesBillDO.setSalesBillNo(salesBillNo);
                return salesBillMapper.updateBySalesBillNo(salesBillDO) > 0;
            }
        }
        return true;
    }

    @Transactional(rollbackFor = Exception.class)
    public ErrorCode autoAdd(SalesBillVO salesBillVO, String userId, String orgId) throws Exception {

        List<SalesBillDetailVO> voList = salesBillVO.getDetailVOList();
        if (CollectionUtils.isEmpty(voList)){
            throw new Exception("已出库零件不能为空");
        }
        String id = genClient.newGuidText().getValue();
        if (StringUtils.isBlank(id)) {
            throw new Exception("新增销售单主键失败");
        }

        Date date = new Date();
        String salasBillNo = genDocumentService.getDocumentNo(BillDesc.SalesNo);
        salesBillVO.setStatus((short)2);//已出库
        salesBillVO.setOutboundStatus(2);
        salesBillVO.setCreateOutboundStatus(2);//已完成
        salesBillVO.setOutboundDate(voList.get(0).getCreateDate());//出库时间

        //校验是否为同一销售出库单
        List<String> saleOutBillNos = voList.stream().filter(detailVO->StringUtils.isNotEmpty(detailVO.getSalesOutBillNo()))
                .map(SalesBillDetailVO::getSalesOutBillNo).distinct().collect(Collectors.toList());
        if (CollectionUtils.isEmpty(saleOutBillNos)){
            throw new Exception("已出库零件销售出库单号不能为空");
        }
        if (saleOutBillNos.size() > 1){
            throw new Exception("已出库零件属于不同销售出库单，请重新选择");
        }

        List<SalesBillDetailVO> detailVOList = getDetailVOList(salesBillVO, userId, orgId, date, salasBillNo);
        ErrorCode errorCode = salesBillDetailService.add(detailVOList);
        if (ErrorCode.Success != errorCode) {
            throw new Exception("新增销售单详情失败");
        }

        SalesBillDO record = getSalesBillDO(salesBillVO, userId, orgId, id, date, salasBillNo);
        int insertCount = salesBillMapper.insertSelective(record);
        if (insertCount <= 0) {
            throw new Exception("新增销售单失败");
        }

        //更新销售出库单状态
        //查询销售出库单，并更新状态及价格等
        SalesOutBillDO salesOutBillDO = salesOutBillMapper.selectBySalesOutBillNo(saleOutBillNos.get(0));

        salesOutBillDO.setOrgId(orgId);
        salesOutBillDO.setSalesBillNo(salasBillNo);
        salesOutBillDO.setSalesOutBillNo(saleOutBillNos.get(0));
        salesOutBillDO.setCreateSaleStatus((short)1);//已创建
        salesOutBillDO.setClientName(record.getClientName());
        salesOutBillDO.setServicePersonName(record.getServicePersonName());//销售人员
        salesOutBillDO.setConsignee(record.getConsignee());
        salesOutBillDO.setContactPhone(record.getContactPhone());
        salesOutBillDO.setReceiptAddress(record.getReceiptAddress());
        salesOutBillDO.setTotalPrice(record.getAdjustedTotalPrice());//总价
        salesOutBillDO.setCostTotal(record.getCostTotal());//总成本
        salesOutBillDO.setBillType(record.getBillType());
        salesOutBillDO.setUpdateDate(new Date());
        salesOutBillDO.setUpdateId(userId);
        int outCount = salesOutBillMapper.updateByOutBillNo(salesOutBillDO);
        if (outCount <= 0) {
            throw new Exception("更新销售单出库单失败");
        }

        //更新出库单详情
        for (SalesBillDetailVO billDetailVO : detailVOList){
            SalesOutBillDetailDO billDetailDO = new SalesOutBillDetailDO();
            billDetailDO.setId(billDetailVO.getId());
            billDetailDO.setSalesBillNo(salasBillNo);
            billDetailDO.setOrgId(orgId);
            billDetailDO.setSinglePrice(billDetailVO.getAdjustedSinglePrice());
            billDetailDO.setUpdateDate(new Date());
            billDetailDO.setUpdateId(userId);

            int outDetailCount = salesOutBillDetailMapper.updateByPrimaryKeySelective(billDetailDO);
            if (outDetailCount <= 0) {
                throw new Exception("更新销售单出库单失败");
            }
        }

        //创建应收记录
        if (needGenArap(orgId)) {
            salesBillOutService.balanceAdd(salesOutBillDO, orgId);
        }

        return ErrorCode.Success;
    }

    /**
     * 2019-12-02 代理商和施维英生成应收记录（施维英此处功能为赠送出库）
     *
     * @return
     */
    private boolean needGenArap(String orgId) {
        CompanyInfoVO infoVO = companyInfoService.info(orgId);
        if (null == infoVO) {
            return false;
        }
        return (infoVO.getIsSap() != null && infoVO.getIsSap() == 0)
                || CompanyUtil.isSWY(infoVO.getSapCode());
    }
}
